#include "LoggerMng.h"

LoggerMng *LoggerMng::m_pInstance = nullptr;
#if (INIT_GARBAGE == 1)
LoggerMng::GarbageCollector gc;
#endif

unique_ptr<LoggerMng> LoggerMng::m_ptrInstance(nullptr);


LoggerMng &LoggerMng::Instance()
{
    static LoggerMng instance;                          // 静态局部变量, 要使用引用返回值, 否则调用一次就构建一次,浪费资源
    return instance;
}

LoggerMng *LoggerMng::getInstance()
{
    if ( m_pInstance == nullptr )                       // 静态成员使用指针的话，程序退出时无法指针类的析构函数
    {
        m_pInstance = new LoggerMng();
    }
    return m_pInstance;
}

unique_ptr<LoggerMng> &LoggerMng::ptrInstance()
{
    if ( m_ptrInstance == nullptr )
    {
        m_ptrInstance.reset(new LoggerMng());
    }
    return m_ptrInstance;
}

bool LoggerMng::init(const string &filePath)
{
    if ( filePath.empty() )
    {
        return false;
    }

    // 开启写日志线程
    m_threadPtr.reset(new std::thread(std::bind(&LoggerMng::threadWriteLog, this)));

    // 创建日志文件
    time_t t = time(NULL);
    struct tm* sys_tm = localtime(&t);
    struct tm my_tm = *sys_tm;

    char buf[256] = {0};
    snprintf(buf, 255, "%d_%02d_%02d.log",my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday);
    string fileName = buf;

    m_today = my_tm.tm_mday;

    m_pFile = fopen(fileName.c_str(), "a");
    return (m_pFile != nullptr);
}

void LoggerMng::writeLog(const LoggerMng::LOG_LEVEL &level, const char *format, ...)
{
    string levelStr = level2Str(level);

    struct timeval now = {0,0};
    gettimeofday(&now, NULL);
    time_t t = now.tv_sec;
    struct tm* sys_tm = localtime(&t);
    struct tm my_tm = *sys_tm;

    // 时间不是同一天时，先关闭之前的文件，重新打开新的文件
    if ( m_today != my_tm.tm_mday )
    {
        m_today = my_tm.tm_mday;

        // 关闭之前的文件
        fflush(m_pFile);
        fclose(m_pFile);

        char newFileName[256] = {0};
        snprintf(newFileName, 256, "%d_%02d_%02d.log",my_tm.tm_year+1900, my_tm.tm_mon+1, my_tm.tm_mday);

        m_pFile = fopen(newFileName, "a");
        if ( m_pFile == nullptr ){
            return ;
        }
    }

    char msg[256] = {0};
    va_list valist;
    va_start(valist, format);
    vsnprintf(msg, 256, format, valist);            // 取可变参数保存到缓冲区
    va_end(valist);

    char content[512] = { 0 };
    snprintf(content, 512, "[%04d-%02d-%02d %02d:%02d:%02d.%ld][%s:%d]%s\n",
             sys_tm->tm_year + 1900, sys_tm->tm_mon + 1, sys_tm->tm_mday, sys_tm->tm_hour, sys_tm->tm_min, sys_tm->tm_sec, now.tv_usec/1000, __FILE__, __LINE__, msg);

    {
        // {}作用域结束后释放锁
        std::unique_lock<std::mutex> uniqueLock(m_mutex);
        m_strList.emplace_back(string(content));            // 从末尾添加数据 - emplace_back效率比push_back高
    }

    m_conVar.notify_one();
}

void LoggerMng::threadWriteLog()
{
    while( !m_isExit )
    {
        std::unique_lock<std::mutex> uniqueLck(m_mutex);
        // 避免虚假唤醒
        while (m_strList.empty())
        {
            if (m_isExit){
                return;
            }
            m_conVar.wait(uniqueLck);
        }

        string str = m_strList.front();
        std::cout << "write str: " << str << endl;
        fputs(str.c_str(), m_pFile);
        fflush(m_pFile);
        m_strList.pop_front();
    }
}

LoggerMng::LoggerMng()
{
}

string LoggerMng::level2Str(const LoggerMng::LOG_LEVEL &level)
{
    if ( level == LEVEL_DEBUG ) return string("Debug");
    if ( level == LEVEL_INFO ) return string("Info");
    if ( level == LEVEL_WARN ) return string("Warn");
    if ( level == LEVEL_ERROR ) return string("Error");
    return string("Debug");
}

LoggerMng::~LoggerMng()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    m_isExit = true;

    m_conVar.notify_one();

    m_threadPtr->join();

    if ( m_pFile )
    {
        fclose(m_pFile);
        m_pFile = nullptr;
    }
}
